use pest::Parser;
use pest::iterators::Pair;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "expression.pest"]
pub struct SysYParser;

// #[derive(Debug, PartialEq)]
// pub enum Token {
//     Integer(i64),
// }

fn parse_token(pair: Pair<Rule>) {
    match pair.as_rule() {
        Rule::program
        | Rule::func
        | Rule::block
        | Rule::statement
        | Rule::decl
        | Rule::var_decl
        | Rule::expr
        | Rule::assign
        | Rule::logical
        | Rule::init
        | Rule::equality
        | Rule::relational
        | Rule::additive
        | Rule::multiplicative
        | Rule::unary
        | Rule::primary
        | Rule::TYPE
        | Rule::args
        | Rule::param
        | Rule::params => {
            for token in pair.into_inner() {
                parse_token(token);
            }
        }
        Rule::INTEGER_CONST => {
            let line = pair.line_col().0;
            for number in pair.into_inner() {
                let mut decimal: u64 = 0;
                match number.as_rule() {
                    Rule::HEXADACIMAL => {
                        decimal = u64::from_str_radix(&number.as_str()[2..], 16).unwrap();
                    }
                    Rule::OCTAL_EXPLICIT => {
                        decimal = u64::from_str_radix(&number.as_str()[2..], 8).unwrap();
                    }
                    Rule::OCTAL_TRADITIONAL => {
                        decimal = u64::from_str_radix(&number.as_str()[1..], 8).unwrap();
                    }
                    Rule::DECIMAL => {
                        decimal = number.as_str().parse::<u64>().unwrap();
                    }
                    _ => (),
                }
                println!("INTEGER_CONST {} at Line {}.", decimal, line);
            }
        }
        Rule::EOI => (),
        _ => println!(
            "{:?} {} at Line {}.",
            pair.as_rule(),
            pair.as_str(),
            pair.as_span().start_pos().line_col().0
        ),
    }
}

pub fn tokenize(input: &str) {
    match SysYParser::parse(Rule::program, input) {
        Ok(pairs) => {
            for token in pairs.into_iter() {
                parse_token(token);
            }
        }
        Err(e) => {
            if let pest::error::InputLocation::Pos(pos) = e.location {
                if pos < input.len() {
                    let error_char = input.chars().nth(pos).unwrap_or(' ');
                    if let pest::error::LineColLocation::Pos((line, _)) = e.line_col {
                        println!(
                            "Error type A at Line {:?}: Mysterious character \"{}\"",
                            line, error_char
                        )
                    }
                }
            }
        }
    }
}
